{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "4e2a9393-7767-488e-a8bf-27c12dca35bd",
   "metadata": {},
   "outputs": [],
   "source": [
    "# imports\n",
    "\n",
    "import os\n",
    "import requests\n",
    "from dotenv import load_dotenv\n",
    "from bs4 import BeautifulSoup\n",
    "from IPython.display import Markdown, display\n",
    "from openai import OpenAI\n",
    "\n",
    "# If you get an error running this cell, then please head over to the troubleshooting notebook!"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "92d0aa2b-8e2f-4c1b-8b81-646faf4cd8c5",
   "metadata": {},
   "source": [
    "# And now the change for Ollama\n",
    "\n",
    "1. No environment variables are needed (no keys) so this part has been removed\n",
    "\n",
    "2. The OpenAI client library is being initialized to point to your local computer for Ollama\n",
    "\n",
    "3. You need to have installed Ollama on your computer, and run `ollama run llama3.2` in a Powershell or Terminal if you haven't already\n",
    "\n",
    "4. Anywhere in this lab that it used to have **gpt-4o-mini** it now has **lama3.2**\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "019974d9-f3ad-4a8a-b5f9-0a3719aea2d3",
   "metadata": {},
   "outputs": [],
   "source": [
    "# Here it is - see the base_url\n",
    "\n",
    "openai = OpenAI(base_url='http://localhost:11434/v1', api_key='ollama')\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "442fc84b-0815-4f40-99ab-d9a5da6bda91",
   "metadata": {},
   "source": [
    "# Let's make a quick call to a Frontier model to get started, as a preview!"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "a58394bf-1e45-46af-9bfd-01e24da6f49a",
   "metadata": {},
   "outputs": [],
   "source": [
    "# To give you a preview -- calling OpenAI with these messages is this easy. Any problems, head over to the Troubleshooting notebook.\n",
    "\n",
    "message = \"Hello, Llama! This is my first ever message to you! Hi!\"\n",
    "response = openai.chat.completions.create(model=\"llama3.2\", messages=[{\"role\":\"user\", \"content\":message}])\n",
    "print(response.choices[0].message.content)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "2aa190e5-cb31-456a-96cc-db109919cd78",
   "metadata": {},
   "source": [
    "## OK onwards with our first project"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "c5e793b2-6775-426a-a139-4848291d0463",
   "metadata": {},
   "outputs": [],
   "source": [
    "# A class to represent a Webpage\n",
    "# If you're not familiar with Classes, check out the \"Intermediate Python\" notebook\n",
    "\n",
    "# Some websites need you to use proper headers when fetching them:\n",
    "headers = {\n",
    " \"User-Agent\": \"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/117.0.0.0 Safari/537.36\"\n",
    "}\n",
    "\n",
    "class Website:\n",
    "\n",
    "    def __init__(self, url):\n",
    "        \"\"\"\n",
    "        Create this Website object from the given url using the BeautifulSoup library\n",
    "        \"\"\"\n",
    "        self.url = url\n",
    "        response = requests.get(url, headers=headers)\n",
    "        soup = BeautifulSoup(response.content, 'html.parser')\n",
    "        self.title = soup.title.string if soup.title else \"No title found\"\n",
    "        for irrelevant in soup.body([\"script\", \"style\", \"img\", \"input\"]):\n",
    "            irrelevant.decompose()\n",
    "        self.text = soup.body.get_text(separator=\"\\n\", strip=True)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "2ef960cf-6dc2-4cda-afb3-b38be12f4c97",
   "metadata": {},
   "outputs": [],
   "source": [
    "# Let's try one out. Change the website and add print statements to follow along.\n",
    "\n",
    "ed = Website(\"https://sohanpatharla.vercel.app/about\")\n",
    "print(ed.title)\n",
    "print(\"Title is printed above\")\n",
    "print(ed.text)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "abdb8417-c5dc-44bc-9bee-2e059d162699",
   "metadata": {},
   "outputs": [],
   "source": [
    "# Define our system prompt - you can experiment with this later, changing the last sentence to 'Respond in markdown in Spanish.\"\n",
    "\n",
    "system_prompt = \"You are an assistant that analyzes the contents of a website \\\n",
    "and provides a short summary, ignoring text that might be navigation related. \\\n",
    "Respond in markdown.\""
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "f0275b1b-7cfe-4f9d-abfa-7650d378da0c",
   "metadata": {},
   "outputs": [],
   "source": [
    "# A function that writes a User Prompt that asks for summaries of websites:\n",
    "\n",
    "def user_prompt_for(website):\n",
    "    user_prompt = f\"You are looking at a website titled {website.title}\"\n",
    "    user_prompt += \"\\nThe contents of this website is as follows; \\\n",
    "please provide a short summary of this website in markdown. \\\n",
    "If it includes news or announcements, then summarize these too.\\n\\n\"\n",
    "    user_prompt += website.text\n",
    "    return user_prompt"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "d06e8d78-ce4c-4b05-aa8e-17050c82bb47",
   "metadata": {},
   "source": [
    "## And now let's build useful messages for GPT-4o-mini, using a function"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "0134dfa4-8299-48b5-b444-f2a8c3403c88",
   "metadata": {},
   "outputs": [],
   "source": [
    "# See how this function creates exactly the format above\n",
    "\n",
    "def messages_for(website):\n",
    "    return [\n",
    "        {\"role\": \"system\", \"content\": system_prompt},\n",
    "        {\"role\": \"user\", \"content\": user_prompt_for(website)}\n",
    "    ]"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "16f49d46-bf55-4c3e-928f-68fc0bf715b0",
   "metadata": {},
   "source": [
    "## Time to bring it together - the API for OpenAI is very simple!"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "905b9919-aba7-45b5-ae65-81b3d1d78e34",
   "metadata": {},
   "outputs": [],
   "source": [
    "# And now: call the OpenAI API. You will get very familiar with this!\n",
    "\n",
    "def summarize(url):\n",
    "    website = Website(url)\n",
    "    response = openai.chat.completions.create(\n",
    "        model = \"llama3.2\",\n",
    "        messages = messages_for(website)\n",
    "    )\n",
    "    return response.choices[0].message.content"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "3d926d59-450e-4609-92ba-2d6f244f1342",
   "metadata": {},
   "outputs": [],
   "source": [
    "# A function to display this nicely in the Jupyter output, using markdown\n",
    "\n",
    "def display_summary(url):\n",
    "    summary = summarize(url)\n",
    "    display(Markdown(summary))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "3018853a-445f-41ff-9560-d925d1774b2f",
   "metadata": {},
   "outputs": [],
   "source": [
    "display_summary(\"https://sohanpatharla.vercel.app/about\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "b3bcf6f4-adce-45e9-97ad-d9a5d7a3a624",
   "metadata": {},
   "source": [
    "# Let's try more websites\n",
    "\n",
    "Note that this will only work on websites that can be scraped using this simplistic approach.\n",
    "\n",
    "Websites that are rendered with Javascript, like React apps, won't show up. See the community-contributions folder for a Selenium implementation that gets around this. You'll need to read up on installing Selenium (ask ChatGPT!)\n",
    "\n",
    "Also Websites protected with CloudFront (and similar) may give 403 errors - many thanks Andy J for pointing this out.\n",
    "\n",
    "But many websites will work just fine!"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "45d83403-a24c-44b5-84ac-961449b4008f",
   "metadata": {},
   "outputs": [],
   "source": [
    "display_summary(\"https://openai.com\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "75e9fd40-b354-4341-991e-863ef2e59db7",
   "metadata": {},
   "outputs": [],
   "source": [
    "display_summary(\"https://anthropic.com\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "490381df-3d03-4aaa-8f29-c5c10ace0ab5",
   "metadata": {},
   "source": [
    "## Email Subject Suggestion based on the letter body"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "00743dac-0e70-45b7-879a-d7293a6f68a6",
   "metadata": {},
   "outputs": [],
   "source": [
    "# Step 1: Create your prompts\n",
    "\n",
    "system_prompt = \"\"\"You are an assistant that analyzes the contents of an email letter body \\\n",
    "and provide a appropriate short subject line for that email,based on that email body. \\\n",
    "\"\"\"\n",
    "user_prompt = \"\"\"\n",
    "    \\nThe contents of an email body is as follows; \\\n",
    "understand the content in that well and provide me a appropriate subject based on the text content in it. \\\n",
    "Understand the sentiment of the email and choose the subject type to be formal or informal or anything.\\n\\n\n",
    "\"\"\"\n",
    "\n",
    "# Step 2: Make the messages list\n",
    "\n",
    "messages = [\n",
    "    {\"role\": \"system\", \"content\": system_prompt},\n",
    "    \n",
    "    {\"role\": \"user\", \"content\": user_prompt + \"\"\"\n",
    "Hey John, just wanted to say thanks for your help with the move last weekend! Couldn't have done it without you.\n",
    "\"\"\"},\n",
    "\n",
    "    {\"role\": \"user\", \"content\": user_prompt + \"\"\"\n",
    "Dear Hiring Manager, I am writing to express my interest in the Marketing Manager position listed on your company’s website.\n",
    "\"\"\"},\n",
    "\n",
    "    {\"role\": \"user\", \"content\": user_prompt + \"\"\"\n",
    "We are excited to invite you to our annual developer conference taking place in San Francisco this July. Register today to secure your spot!\n",
    "\"\"\"},\n",
    "\n",
    "    {\"role\": \"user\", \"content\": user_prompt + \"\"\"\n",
    "Hello, I'm following up on the support ticket I submitted last week regarding the issue with logging into my account. I still haven’t received a resolution.\n",
    "\"\"\"},\n",
    "\n",
    "    {\"role\": \"user\", \"content\": user_prompt + \"\"\"\n",
    "Congratulations! You've been selected as one of our winners in the Spring Giveaway Contest. Claim your prize by replying to this email.\n",
    "\"\"\"},\n",
    "\n",
    "    {\"role\": \"user\", \"content\": user_prompt + \"\"\"\n",
    "Good morning team, just a reminder that our Q2 strategy meeting is scheduled for 10 AM tomorrow in Conference Room B.\n",
    "\"\"\"},\n",
    "\n",
    "    {\"role\": \"user\", \"content\": user_prompt + \"\"\"\n",
    "Hi Mom, the flight was fine, and I got here safely. The weather’s great and the Airbnb is cozy. I’ll send pictures soon!\n",
    "\"\"\"},\n",
    "\n",
    "    {\"role\": \"user\", \"content\": user_prompt + \"\"\"\n",
    "To whom it may concern, I am very dissatisfied with the quality of the product I received and would like a full refund.\n",
    "\"\"\"}\n",
    "]\n",
    "\n",
    "\n",
    "# Step 3: Call OpenAI\n",
    "\n",
    "response =openai.chat.completions.create(model=\"llama3.2\",messages=messages)\n",
    "\n",
    "# Step 4: print the result\n",
    "# response = openai.chat.completions.create(model=\"llama3.2\", messages=messages)\n",
    "#print(response.choices[0].message.content)\n",
    "print(response.choices[0].message.content)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "36ed9f14-b349-40e9-a42c-b367e77f8bda",
   "metadata": {},
   "source": [
    "## An extra exercise for those who enjoy web scraping\n",
    "\n",
    "You may notice that if you try `display_summary(\"https://openai.com\")` - it doesn't work! That's because OpenAI has a fancy website that uses Javascript. There are many ways around this that some of you might be familiar with. For example, Selenium is a hugely popular framework that runs a browser behind the scenes, renders the page, and allows you to query it. If you have experience with Selenium, Playwright or similar, then feel free to improve the Website class to use them. In the community-contributions folder, you'll find an example Selenium solution from a student (thank you!)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "bf424661-6c39-4398-9983-9b02df7e9311",
   "metadata": {},
   "outputs": [],
   "source": [
    "!pip install selenium"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "f4484fcf-8b39-4c3f-9674-37970ed71988",
   "metadata": {},
   "outputs": [],
   "source": [
    "#Parse webpages which is designed using JavaScript heavely\n",
    "# download the chorme driver from here as per your version of chrome - https://developer.chrome.com/docs/chromedriver/downloads\n",
    "from selenium import webdriver\n",
    "from selenium.webdriver.chrome.service import Service\n",
    "from selenium.webdriver.common.by import By\n",
    "from selenium.webdriver.chrome.options import Options\n",
    "\n",
    "PATH_TO_CHROME_DRIVER = r'C:\\Users\\sohan\\Downloads\\chromedriver-win64\\chromedriver-win64\\chromedriver.exe'\n",
    "\n",
    "class Website:\n",
    "    url: str\n",
    "    title: str\n",
    "    text: str\n",
    "\n",
    "    def __init__(self, url):\n",
    "        self.url = url\n",
    "\n",
    "        options = Options()\n",
    "\n",
    "        options.add_argument(\"--no-sandbox\")\n",
    "        options.add_argument(\"--disable-dev-shm-usage\")\n",
    "\n",
    "        service = Service(PATH_TO_CHROME_DRIVER)\n",
    "        driver = webdriver.Chrome(service=service, options=options)\n",
    "        driver.get(url)\n",
    "\n",
    "        input(\"Please complete the verification in the browser and press Enter to continue...\")\n",
    "        page_source = driver.page_source\n",
    "        driver.quit()\n",
    "\n",
    "        soup = BeautifulSoup(page_source, 'html.parser')\n",
    "        self.title = soup.title.string if soup.title else \"No title found\"\n",
    "        for irrelevant in soup([\"script\", \"style\", \"img\", \"input\"]):\n",
    "            irrelevant.decompose()\n",
    "        self.text = soup.get_text(separator=\"\\n\", strip=True)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "56989f9b-8efb-4cfb-a355-1c50d36cc9b2",
   "metadata": {
    "scrolled": true
   },
   "outputs": [],
   "source": [
    "display_summary(\"https://openai.com\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "59b15b6d-3743-44a0-9dd4-23c9e9da6e3e",
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.11.12"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
